﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using OpenLab.BLL.ViewModel;

namespace OpenLab.UI.Helper
{
    public static class StaticVar
    {
        public static bool LogedIn = false;
        public static object CurrentUser = null;
        public static BindingSource BsClients = new BindingSource();
        public static DateTime? DerniereTimeChargementClient = DateTime.Now.AddYears(-1);


    }
    public static class Encryptor
    {
        public static string MD5Hash(string text)
        {
            MD5 md5 = new MD5CryptoServiceProvider();

            //compute hash from the bytes of text
            md5.ComputeHash(Encoding.ASCII.GetBytes(text));

            //get hash result after compute it
            byte[] result = md5.Hash;

            StringBuilder strBuilder = new StringBuilder();
            foreach (byte b in result)
            {
                //change it into 2 hexadecimal digits
                //for each byte
                strBuilder.Append(b.ToString("x2"));
            }
            return strBuilder.ToString();
        }
    }
    public static class Utile
    {
        public static DataTable ListToDatatable<T>(List<T> data)
        {
            PropertyDescriptorCollection props =
                TypeDescriptor.GetProperties(typeof(T));
            DataTable table = new DataTable();
            for (int i = 0; i < props.Count; i++)
            {
                PropertyDescriptor prop = props[i];
                if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                    table.Columns.Add(prop.Name, prop.PropertyType.GetGenericArguments()[0]);
                else
                    table.Columns.Add(prop.Name, prop.PropertyType);
            }
            object[] values = new object[props.Count];
            foreach (T item in data)
            {
                for (int i = 0; i < values.Length; i++)
                {
                    values[i] = props[i].GetValue(item);
                }
                table.Rows.Add(values);
            }
            return table;
        }
        public static string UglifyTextAr(string name)
        {
            return name.Replace(" ", "").Replace(".", "").Replace(",", "").Replace(":", "").Replace("''", "").Replace("،", "").Replace("{", "").Replace("}", "").Replace("[", "").Replace("]", "").Replace("=", "").Replace("+", "").Replace("_", "").Replace("-", "").Replace("(", "").Replace(")", "").Replace("&", "").Replace("*", "").Replace("^", "").Replace("%", "").Replace("$", "").Replace("#", "").Replace("@", "").Replace("!", "").Replace("÷", "").Replace("‘ُ", "").Replace("؛", "").Replace("×", "").Replace("<", "").Replace(">", "").Replace("إ", "ا").Replace("لإ", "ل").Replace("''", "").Replace("/", "").Replace("،", "").Replace("ـ", "").Replace("أ", "ا").Replace("لأ", "ل").Replace("~ْ", "").Replace("لآ", "ل").Replace("آ", "ا").Replace("’", "").Replace(",", "").Replace("؟", "").Replace("ئ", "ا").Replace("ء", "ا").Replace("ؤ", "ا").Replace("لا", "ل").Replace("ي", "ى").Replace("ة", "ه").Replace("و", "ا").Replace("ض", "ظ").Replace("ث", "ت").Replace("س", "ش").Replace("اا", "ا").Replace("ى", "ا");
        }
        #region int to nobre en lettre francais
        private static string[] m_Unite = new string[] { "zero ", "un ", "deux ", "trois ", "quatre ", "cinq ", "six ", "sept ", "huit ", "neuf " };
        private static string[] m_FirstDizaine = new string[] { String.Empty, "onze ", "douze ", "treize ", "quatorze ", "quinze ", "seize ", "dix-sept ", "dix-huit ", "dix-neuf " };
        private static string[] m_Dizaine = new string[] { String.Empty, "dix ", "vingt ", "trente ", "quarante ", "cinquante ", "soixante ", "soixante ", "quatre-vingt ", "quatre-vingt " };
        private static string[] m_CentMille = new string[] { "cent ", "cents ", "mille ", "million ", "millions ", "milliard ", "milliards " };

        private static string m_PrefixAnd = "et ";

        private static string[] m_Devise = new string[] { "dinar", "dinars" };

        private static string[] m_Centime = new string[] { "millime", "millimes" };

        public static string IntegerToFrenchWords(int p_Number)
        {
            if (p_Number == 0)
                return m_Unite[0]; // zéro

            bool isNumberNeg = false;
            if (p_Number < 0)
            {
                isNumberNeg = true;
                p_Number = p_Number * -1;
                // PB si p_Number = -2147483648 => p_Number * -1 = -2147483648,
                // car la valeur max d'un entier est 2147483647 et pas 2147483648
                if (p_Number == Int32.MinValue)
                    throw new ArgumentException("Impossible de convertir en lettres le nombre " + p_Number, "p_Number");
            }

            // Déclarations
            int centaine, dizaine, unite, reste, y;
            bool is10or70or90 = false;
            string intInWords = String.Empty;

            reste = (int)p_Number;

            for (int i = 1000000000; i >= 1; i /= 1000)
            {
                y = reste / i;
                if (y != 0)
                {
                    centaine = y / 100;
                    dizaine = (y - centaine * 100) / 10;
                    unite = y - (centaine * 100) - (dizaine * 10);

                    // Centaines
                    if (centaine == 1)
                        intInWords += m_CentMille[0];
                    else if (centaine > 1)
                    {
                        intInWords += m_Unite[centaine];
                        if ((dizaine == 0) && (unite == 0)) intInWords += m_CentMille[1];
                        else intInWords += m_CentMille[1];
                    }

                    // Convertit les dizaines et unités en lettres
                    intInWords += GetUniteAndDizaineWords(dizaine, unite, ref is10or70or90);

                    // Milliers, millions, milliards
                    switch (i)
                    {
                        case 1000000000:
                            if (y > 1) intInWords += m_CentMille[6];
                            else intInWords += m_CentMille[5];
                            break;
                        case 1000000:
                            if (y > 1) intInWords += m_CentMille[4];
                            else intInWords += m_CentMille[3];
                            break;
                        case 1000: // cas particulier si unité = 1 -> pas de préfix "un"
                            intInWords = unite == 1 ? m_CentMille[2] : String.Concat(intInWords, m_CentMille[2]);
                            break;
                    }
                }

                reste -= y * i;
                is10or70or90 = false;
            }

            if (isNumberNeg)
                intInWords = "moins " + intInWords;

            return intInWords;
        }

        public static string CurrencyNumberToFrenchWords(double p_Number)
        {
            if (p_Number == 0)
                return m_Unite[0]; // zéro

            // Déclarations
            int dizaine, unite;
            //bool is10or70or90 = false;
            string intInWords = String.Empty;

            // Récupère la partie entière et détermine la devise au singulier/pluriel
            int partEntiere = (int)p_Number;
            string devise = partEntiere > 1 ? m_Devise[1] : m_Devise[0];

            // Récupère la partie entière
            intInWords = IntegerToFrenchWords(partEntiere);

            // Traitement de la virgule
            decimal chiffreDec;
            chiffreDec = (decimal)(p_Number * 1000) % 1000;
            dizaine = (int)(chiffreDec) / 10;
            unite = (int)chiffreDec - (dizaine * 10);

            // Convertit les dizaines et unités en lettres
            string decInWords = IntegerToFrenchWords((int)chiffreDec);//GetUniteAndDizaineWords(dizaine, unite, ref is10or70or90);

            if (decInWords == String.Empty)
                return String.Concat(intInWords, devise);
            else if (dizaine == 0 && unite == 1)
                return String.Format("{0}{1} et {2}{3}", intInWords, devise, decInWords, m_Centime[0]);
            else
                return String.Format("{0}{1} et {2}{3}", intInWords, devise, decInWords, m_Centime[1]);
        }

        private static string GetUniteAndDizaineWords(int p_Dizaine, int p_Unite, ref bool p_Is10or70or90)
        {
            string numberInWords = String.Empty;

            // dizaines
            if (p_Dizaine == 1) // Flag la dizaine particulière
            {
                p_Is10or70or90 = true;
            }
            else if (p_Dizaine > 1)
            {
                // Concatène avec la dizaine appropriée
                numberInWords += m_Dizaine[p_Dizaine];

                if (p_Dizaine == 7 || p_Dizaine == 9) // Flag la dizaine particulière
                    p_Is10or70or90 = true;
            }


            // unités
            if (p_Unite == 0 && p_Is10or70or90)
            {
                numberInWords += m_Dizaine[1]; // dix
            }
            else if (p_Unite == 1)
            {
                if (p_Dizaine == 7) numberInWords = String.Concat(numberInWords, m_PrefixAnd, m_FirstDizaine[p_Unite]);
                else
                    if (p_Is10or70or90) numberInWords += m_FirstDizaine[p_Unite];
                    else if (p_Dizaine == 8) numberInWords = String.Concat(numberInWords, m_Unite[p_Unite]); // cas particulier 81 pas de "et"
                    else if (p_Dizaine > 1) numberInWords = String.Concat(numberInWords, m_PrefixAnd, m_Unite[p_Unite]);
                    else numberInWords += m_Unite[1];
            }
            else if (p_Unite > 1)
            {
                if (p_Is10or70or90) numberInWords += m_FirstDizaine[p_Unite];
                else numberInWords += m_Unite[p_Unite];
            }

            return numberInWords;
        }
        #endregion
        public static byte[] ReadToEnd(Stream stream)
        {
            long originalPosition = stream.Position;
            stream.Position = 0;

            try
            {
                byte[] readBuffer = new byte[4096];

                int totalBytesRead = 0;
                int bytesRead;

                while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
                {
                    totalBytesRead += bytesRead;

                    if (totalBytesRead == readBuffer.Length)
                    {
                        int nextByte = stream.ReadByte();
                        if (nextByte != -1)
                        {
                            byte[] temp = new byte[readBuffer.Length * 2];
                            Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
                            Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
                            readBuffer = temp;
                            totalBytesRead++;
                        }
                    }
                }

                byte[] buffer = readBuffer;
                if (readBuffer.Length != totalBytesRead)
                {
                    buffer = new byte[totalBytesRead];
                    Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
                }
                return buffer;
            }
            finally
            {
                stream.Position = originalPosition;
            }
        }


        internal static void LoadAllClient()
        {

            Thread th = new Thread(GetClient);
            th.Start();
        }
        private static DataTable _tmpTable;
        private static void GetClient()
        {
            if (StaticVar.DerniereTimeChargementClient != null)
            {
                TimeSpan ts = DateTime.Now - Convert.ToDateTime(StaticVar.DerniereTimeChargementClient);
                if(ts.TotalMinutes<1) return;
            }

            _tmpTable = ListToDatatable(new ListeClientBLL().GetAll().ToList());
            StaticVar.DerniereTimeChargementClient = DateTime.Now;
            if (_tmpTable!=null)
                try
                {
                    StaticVar.BsClients.DataSource = _tmpTable;
                }
                catch
                {
                    Thread.Sleep(500);
                    StaticVar.BsClients.DataSource = _tmpTable;
                }
                
        }
    }
    public static class CrossThreadExtensions
    {
        public static void PerformSafely(this Control target, Action action)
        {
            if (target.InvokeRequired)
            {
                target.Invoke(action);
            }
            else
            {
                action();
            }
        }

        public static void PerformSafely<T1>(this Control target, Action<T1> action, T1 parameter)
        {
            if (target.InvokeRequired)
            {
                target.Invoke(action, parameter);
            }
            else
            {
                action(parameter);
            }
        }

        public static void PerformSafely<T1, T2>(this Control target, Action<T1, T2> action, T1 p1, T2 p2)
        {
            if (target.InvokeRequired)
            {
                target.Invoke(action, p1, p2);
            }
            else
            {
                action(p1, p2);
            }
        }
    }
    public class BindHelper
    {
        protected object src;
        protected string srcProp;
        protected object dest;
        protected string destProp;

        protected PropertyInfo srcPropInfo;
        protected PropertyInfo destPropInfo;

        public BindHelper(object src,
             string srcProp, object dest, string destProp)
        {
            this.src = src;
            this.srcProp = srcProp;
            this.dest = dest;
            this.destProp = destProp;

            Type t1 = src.GetType();
            Type t2 = dest.GetType();

            // Get the PropertyInfo now 
            // rather than in the event handler.
            srcPropInfo = t1.GetProperty(srcProp);
            destPropInfo = t2.GetProperty(destProp);
        }

        public static void Bind(object obj1, string prop1,
                                  object obj2, string prop2)
        {
            string event1 = prop1 + "Changed";
            string event2 = prop2 + "Changed";

            Type t1 = obj1.GetType();
            Type t2 = obj2.GetType();

            EventInfo ei1 = t1.GetEvent(event1);
            EventInfo ei2 = t2.GetEvent(event2);

            BindHelper bh = new BindHelper(obj1, prop1, obj2, prop2);

            // The signature of the event 
            // delegate must be of the form 
            // (object, EventArgs).
            // Although events don't have to be 
            // of this signature, this is a good
            // reason to comply with the .NET guidelines.

            // Unfortunately, .NET 1.1 does not 
            // handle event signatures that are 
            // derived from EventArgs when programatically 
            // adding a generic handler.
            // This "bug" is corrected in .NET 2.0!

            ei1.AddEventHandler(obj1,
                 new EventHandler(bh.SourceChanged));
            //ei2.AddEventHandler(obj2, new EventHandler(bh.DestinationChanged));

            //bh.DestinationChanged(bh, EventArgs.Empty);
        }

        private void SourceChanged(object sender, EventArgs e)
        {
            object val = srcPropInfo.GetValue(src, null);
            destPropInfo.SetValue(dest, val, null);
        }

        private void DestinationChanged(object sender,
                                               EventArgs e)
        {
            object val = destPropInfo.GetValue(dest, null);
            srcPropInfo.SetValue(src, val, null);
        }
    }
    public static class Cryptage
    {
        #region fields pour la lasse cryptage
        const string PassPhrase = "+=newvvdjPs,ds'@#~"; // can be any string
        const string SaltValue = "s@ad8dsdzjzj8?mmas"; // can be any string
        const string HashAlgorithm = "SHA1"; // can be "MD5"
        const int PasswordIterations = 2; // can be any number
        const string InitVector = "95B2c3D805F6plH8"; // must be 16 bytes
        const int KeySize = 256; // can be 192 or 128
        #endregion

        public static string GetEncrypt(string decriptedString)
        {
            return Encrypt(decriptedString, PassPhrase, SaltValue, HashAlgorithm, PasswordIterations, InitVector, KeySize);
        }

        public static string GetDecrypt(string encryptedString)
        {
            return Decrypt(encryptedString, PassPhrase, SaltValue, HashAlgorithm, PasswordIterations, InitVector, KeySize);
        }

        private  static string Encrypt(string plainText, string passPhrase, string saltValue, 
            string hashAlgorithm, int passwordIterations, string initVector, int keySize)
        {
            // Convert strings into byte arrays.
            // Let us assume that strings only contain ASCII codes.
            // If strings include Unicode characters, use Unicode, UTF7, or UTF8 
            // encoding.
            byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
            byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);

            // Convert our plaintext into a byte array.
            // Let us assume that plaintext contains UTF8-encoded characters.
            byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

            // First, we must create a password, from which the key will be derived.
            // This password will be generated from the specified passphrase and 
            // salt value. The password will be created using the specified hash 
            // algorithm. Password creation can be done in several iterations.
            PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, saltValueBytes, hashAlgorithm, passwordIterations);

            // Use the password to generate pseudo-random bytes for the encryption
            // key. Specify the size of the key in bytes (instead of bits).
            byte[] keyBytes = password.GetBytes(keySize / 8);

            // Create uninitialized Rijndael encryption object.
            RijndaelManaged symmetricKey = new RijndaelManaged();

            // It is reasonable to set encryption mode to Cipher Block Chaining
            // (CBC). Use default options for other symmetric key parameters.
            symmetricKey.Mode = CipherMode.CBC;

            // Generate encryptor from the existing key bytes and initialization 
            // vector. Key size will be defined based on the number of the key 
            // bytes.
            ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);

            // Define memory stream which will be used to hold encrypted data.
            MemoryStream memoryStream = new MemoryStream();

            // Define cryptographic stream (always use Write mode for encryption).
            CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
            // Start encrypting.
            cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);

            // Finish encrypting.
            cryptoStream.FlushFinalBlock();

            // Convert our encrypted data from a memory stream into a byte array.
            byte[] cipherTextBytes = memoryStream.ToArray();

            // Close both streams.
            memoryStream.Close();
            cryptoStream.Close();

            // Convert encrypted data into a base64-encoded string.
            string cipherText = Convert.ToBase64String(cipherTextBytes);

            // Return encrypted string.
            return cipherText;
        }

        private static string Decrypt(string cipherText, string passPhrase, 
            string saltValue, string hashAlgorithm, int passwordIterations, string initVector, int keySize)
        {
            // Convert strings defining encryption key characteristics into byte
            // arrays. Let us assume that strings only contain ASCII codes.
            // If strings include Unicode characters, use Unicode, UTF7, or UTF8
            // encoding.
            byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);
            byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);

            // Convert our ciphertext into a byte array.
            byte[] cipherTextBytes = Convert.FromBase64String(cipherText);

            // First, we must create a password, from which the key will be 
            // derived. This password will be generated from the specified 
            // passphrase and salt value. The password will be created using
            // the specified hash algorithm. Password creation can be done in
            // several iterations.
            PasswordDeriveBytes password = new PasswordDeriveBytes(passPhrase, saltValueBytes, hashAlgorithm, passwordIterations);

            // Use the password to generate pseudo-random bytes for the encryption
            // key. Specify the size of the key in bytes (instead of bits).
            byte[] keyBytes = password.GetBytes(keySize / 8);

            // Create uninitialized Rijndael encryption object.
            RijndaelManaged symmetricKey = new RijndaelManaged();

            // It is reasonable to set encryption mode to Cipher Block Chaining
            // (CBC). Use default options for other symmetric key parameters.
            symmetricKey.Mode = CipherMode.CBC;

            // Generate decryptor from the existing key bytes and initialization 
            // vector. Key size will be defined based on the number of the key 
            // bytes.
            ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes);

            // Define memory stream which will be used to hold encrypted data.
            MemoryStream memoryStream = new MemoryStream(cipherTextBytes);

            // Define cryptographic stream (always use Read mode for encryption).
            CryptoStream cryptoStream = new CryptoStream(memoryStream,
            decryptor,
            CryptoStreamMode.Read);

            // Since at this point we don't know what the size of decrypted data
            // will be, allocate the buffer long enough to hold ciphertext;
            // plaintext is never longer than ciphertext.
            byte[] plainTextBytes = new byte[cipherTextBytes.Length];

            // Start decrypting.
            int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);

            // Close both streams.
            memoryStream.Close();
            cryptoStream.Close();

            // Convert decrypted data into a string. 
            // Let us assume that the original plaintext string was UTF8-encoded.
            string plainText = Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);

            // Return decrypted string.   
            return plainText;
        }
    }
}
